﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Game2048WithCSharp
{
    internal class CubeMoveController
    {
        private Action<Control> removeControl;
        private Action<GameState> checkGameState;
        public Action StartOutTask, EndOutTask;
        private Action<int[,], GameState> GenerateNewCube;
        List<(int[,], GameState)> newCubeTask = new List<(int[,], GameState)>();
        List<Cube> cubes;
        private List<(CubeMove[], GameState)> cubeMoveTasks = new List<(CubeMove[], GameState)>();
        public void Init(Action<Control> removeControl, 
            Action<GameState> checkGameState, 
            List<Cube> cubes,
            Action StartOutTask, Action EndOutTask,
            Action<int[,], GameState> GenerateNewCube)
        {
            this.removeControl = removeControl;
            this.checkGameState = checkGameState;
            this.cubes = cubes;
            this.StartOutTask = StartOutTask;
            this.EndOutTask = EndOutTask;
            this.GenerateNewCube = GenerateNewCube;
        }
        public void Clear()
        {
            cubeMoveTasks.Clear();
        }
        public void TimeUpdate(double DeltaTime)
        {
            if (cubeMoveTasks.Count == 0) { return; }
            bool TaskComplete = true;
            foreach (Cube cube in cubes)
            {
                if (!cube.UpdateMove(DeltaTime))
                {
                    TaskComplete = false;
                }
            }
            if (TaskComplete)
            {
                EndTask(cubeMoveTasks[0].Item2);
                cubeMoveTasks.RemoveAt(0);
                if (cubeMoveTasks.Count > 0)
                {
                    StartTask(cubeMoveTasks[0].Item1, cubes);
                }
            } else
            {
                for (int i = 0; i < cubes.Count; i++)
                {
                    for (int j = i + 1; j < cubes.Count; j++)
                    {
                        if (cubes[i].Equal(cubes[j]) && cubes[i].TaskComplete && cubes[j].TaskComplete)
                        {
                            cubes[i].Value = cubes[i].Value * 2;
                            removeControl(cubes[j]);
                            cubes.RemoveAt(j);
                            break;
                        }
                    }
                }
            }
        }

        public void AddCubeMoveTask(CubeMove[] cubeMove, GameState gameState)
        {
            cubeMoveTasks.Add((cubeMove, gameState));
            if (cubeMoveTasks.Count == 1)
            {
                StartTask(cubeMove, cubes);
            }
        }
        public void AddGenerateNewCubeTask(int[,] newCube, GameState gameState)
        {
            if (cubeMoveTasks.Count == 0)
            {
                GenerateNewCube(newCube, gameState);
            } 
            else
            {
                newCubeTask.Add((newCube, gameState));
            }
        }
        private void EndTask(GameState gameState)
        {
            for(int i = 0; i < cubes.Count; i++)
            {
                for (int j = i + 1;  j < cubes.Count; j++)
                {
                    if (cubes[i].Equal(cubes[j]))
                    {
                        cubes[i].Value = cubes[i].Value * 2;
                        removeControl(cubes[j]);
                        cubes.RemoveAt(j);
                        break;
                    }
                }
            }
            foreach ((int[,] newCube, GameState gs) in newCubeTask)
            {
                GenerateNewCube(newCube, gs);
            }
            if (newCubeTask.Count == 0)
                checkGameState(gameState);
            newCubeTask.Clear();
            EndOutTask();
        }
        private void StartTask(CubeMove[] cubeMoves, List<Cube> cubes)
        {
            StartOutTask();
            double taskTime = 0;
            foreach (Cube cube in cubes)
            {
                foreach (CubeMove cubeMove in cubeMoves)
                {
                    if (cubeMove.OldX == cubeMove.NewX && cubeMove.OldY == cubeMove.NewY) continue;
                    if (cube.x == cubeMove.OldX && cube.y == cubeMove.OldY)
                    {
                        cube.StartMove(cubeMove.NewX, cubeMove.NewY);
                        taskTime = Math.Max(taskTime, cube.TaskTotalTime);
                        break;
                    }
                }
            }
        }
    }
}
